#ifndef AI_H
#define AI_H



#include "init.h"
#include "rules.h"
#include "units.h"
#include "game.h"
#include <map>
#include <list>
#include <string>
#include <iostream>
#include <QObject>
#include <cmath>



class game_state
{

public:

	game_state( unsigned int pl_c, unsigned int c_pl_id, player** pl, array2d< object* >* obj, array2d< unsigned int >* mp, double sc = 0, array2d< unsigned int >* ep = 0, array2d< bool >* rp = 0, array2d< unsigned int >* dp = 0, array2d< unsigned int >* dpn = 0, array2d< unsigned int >* ap = 0 );
	~game_state();

	game_state* clone();

	array2d< unsigned int >* map;
	
	player** plrs;
	unsigned int players_count;
	unsigned int current_player_id;

	array2d< object* >* objects;
	

	array2d< unsigned int >* estimated_places;
	array2d< unsigned int >* dangerous_places;
	array2d< unsigned int >* dangerous_places_nobody;
	array2d< unsigned int >* attackable_places;
	array2d< bool >* reachable_places;

	double score;

};



namespace help_computes
{
	
	array2d< unsigned int >* map_places_estimate( game_state* state );
	array2d< bool >* map_places_reachable( game_state* state );
	array2d< unsigned int >* map_places_dangerous( game_state* state );
	array2d< unsigned int >* map_places_dangerous_nobody( game_state* state );
	array2d< unsigned int >* map_places_attackable( game_state* state );
	double game_state_estimate( game_state* state );

	int ai_test_fire_nobody( unsigned int x, unsigned int y, unsigned int tx, unsigned int ty, game_state* state );
	int ai_test_move_nobody( unsigned int sx, unsigned int sy, unsigned int dx, unsigned int dy, game_state* state );
	int ai_test_fire( unsigned int x, unsigned int y, unsigned int tx, unsigned int ty, game_state* state );
	int ai_test_move( unsigned int sx, unsigned int sy, unsigned int dx, unsigned int dy, game_state* state );
	bool ai_move( unit* u, unsigned int x, unsigned int y, game_state* state );
	bool ai_fire( unit* u, unsigned int x, unsigned int y, game_state* state );
	void ai_next_turn( game_state* state );

	bool apply_command( game_state* state, std::string cmd );

};



class ai_game_state
{

public:

	ai_game_state() {};

	ai_game_state( game_state* gs )
	{
		state = gs->clone();
		command = "";
	};

	ai_game_state( ai_game_state* gs, std::string cmd )
	{
		state = gs->state->clone();
		help_computes::apply_command( state, cmd );
		command = cmd;
	};

	ai_game_state* clone()
	{
		ai_game_state* cl = new ai_game_state( this->state );
		cl->command = command;
		return cl;
	};

	~ai_game_state()
	{
		delete state;
	};

	

	game_state* state;
	std::string command;

};



class algorithm: public QObject
{

	Q_OBJECT

public:

	algorithm() {};

	std::string get_name()
	{
		return name;
	};

	virtual algorithm* clone() = 0;
	void init( player* p );
	player* get_owner();
	void set_owner( player* p );

	virtual void get_commands() = 0;

	template< class This >
	This* clonetpl()
	{
		This* cl = new This();
		cl->set_owner( owner );
		return cl;
	};


protected:

	std::string name;

	player* owner;

	std::list< std::string > commands;


signals:

	void send_command( player*, std::string );


public slots:

	void next_command();

};



class ai_algorithms
{

public:

	static ai_algorithms* get_instance();

	std::map< std::string, algorithm* > algorithm_list;


	int x;


private:

	ai_algorithms( int _x );
	ai_algorithms( const ai_algorithms& );
	ai_algorithms& operator=( const ai_algorithms& x );

};



#endif